package com.hushan.standby.compoment;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.net.NetUtil;
import cn.hutool.core.thread.ThreadUtil;
import jpcap.JpcapCaptor;
import jpcap.JpcapSender;
import jpcap.NetworkInterface;
import jpcap.NetworkInterfaceAddress;
import jpcap.packet.ARPPacket;
import jpcap.packet.EthernetPacket;
import jpcap.packet.Packet;

import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

import static com.hushan.standby.App.LOCAL_HOST;
import static com.hushan.standby.App.VIRTUAL_IP;

public class ArpRequester {

    private static final int MAX_TIMEOUTS = 3;
    private static AtomicInteger timeoutCount = new AtomicInteger(0);

    public static void startMonitor() {
        // 获取网络接口列表
        NetworkInterface[] devices = JpcapCaptor.getDeviceList();
        if (devices.length == 0) {
            System.out.println("No network interfaces found.");
            return;
        }

        // 选择第一个网络接口（可根据需要修改）
        byte[] hardwareAddress = null;
        try {
            hardwareAddress = NetUtil.getHardwareAddress(InetAddress.getByName(LOCAL_HOST));
        } catch (UnknownHostException e) {
            throw new RuntimeException(e);
        }
        NetworkInterface device = null;
        for (int i = 0; i < devices.length; i++) {
            if (Arrays.equals(devices[i].mac_address, hardwareAddress)) {
                device = devices[i];
                System.out.println("Using interface: " + device.name);
            }
        }

        if (device == null) {
            System.out.println("Selected network interface not found.");
            return;
        }
        showAdapterInfo(device);

        // 打开网络接口进行发送
        JpcapSender sender = null;
        JpcapCaptor captor = null;
        try {
            sender = JpcapSender.openDevice(device);
            // 打开网络接口进行接收
            captor = JpcapCaptor.openDevice(device, 65535, true, 100);
            captor.setFilter("arp[6:2] = 2 and src host " + VIRTUAL_IP + " and dst host " + LOCAL_HOST, true);

            // 启动发送和接收任务
            while (true) {
                try {
                    // 发送 ARP 请求
                    String localMacAddress = NetUtil.getMacAddress(InetAddress.getByName(LOCAL_HOST), ":");
                    sendArpPacket(
                            sender,
                            LOCAL_HOST,
                            localMacAddress,
                            VIRTUAL_IP,
                            "FF:FF:FF:FF:FF:FF", true);
                    System.out.println("ARP request sent.");
                    JpcapCaptor finalCaptor = captor;
                    ARPPacket arpReply = arpCap(finalCaptor);
                    if (arpReply != null && arpReply.operation == ARPPacket.ARP_REPLY) {
                        printPkt(arpReply);
                        if (LeaderElection.master.get()) {
                            LeaderElection.startSlave();
                            System.out.println("切换模式：master----->slave");
                        }
                        timeoutCount.set(0); // 重置超时计数
                    } else {
                        timeoutCount.incrementAndGet();
                        if (timeoutCount.get() >= MAX_TIMEOUTS) {
                            System.out.println("Maximum timeouts reached. Exiting program.");
                            System.out.println("Failed to receive ARP reply after " + MAX_TIMEOUTS + " attempts.");
                            if (!LeaderElection.master.get()) {
                                LeaderElection.startMaster();
                                System.out.println("切换模式：slave----->master");
                            }
                            timeoutCount.set(0);
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
                ThreadUtil.safeSleep(500);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            if (sender != null) {
                sender.close();
            }
            if (captor != null) {
                captor.close();
            }
        }
    }

    private static void printPkt(ARPPacket arp) {
        EthernetPacket e = (EthernetPacket) arp.datalink;
        // EthernetPacket
        String sourceAddress = e.getSourceAddress();
        String destinationAddress = e.getDestinationAddress();
        short frameType = e.frametype;

        System.out.println();
        System.out.println("-----------------------------------------ARP reply received.-----------------------------------------");
        System.out.println("源MAC地址: " + sourceAddress);
        System.out.println("目的MAC地址: " + destinationAddress);
        System.out.println("帧类型: " + frameType);

        // arp 内容解析
        short protoType = arp.prototype;
        Object senderProtocolAddress = arp.getSenderProtocolAddress();
        Object senderHardwareAddress = arp.getSenderHardwareAddress();
        Object targetProtocolAddress = arp.getTargetProtocolAddress();
        Object targetHardewareAddress = arp.getTargetHardwareAddress();
        int capturedLength = arp.caplen;
        int packetLength = arp.len;
        long timestamp_s = arp.sec;
        long timestamp_us = arp.usec;
        short hardType = arp.hardtype;
        short hardLength = arp.hlen;
        short operation = arp.operation;

        short arpRequest = ARPPacket.ARP_REQUEST;
        short arpReply = ARPPacket.ARP_REPLY;
        short frameRelay = ARPPacket.HARDTYPE_FRAMERELAY;
        short tokenRing = ARPPacket.HARDTYPE_IEEE802;
        short protoIP = ARPPacket.PROTOTYPE_IP;
        short rarpRequest = ARPPacket.RARP_REQUEST;
        short rarpReply = ARPPacket.RARP_REPLY;
        String data = new String(arp.data);


        System.out.println("协议类型: " + protoType);
        System.out.println("源协议地址和MAC地址: " + senderProtocolAddress + "--" + senderHardwareAddress);
        System.out.println("目的协议地址和MAC地址： " + targetProtocolAddress + "--" + targetHardewareAddress);
        System.out.println("数据报长度: " + capturedLength);
        System.out.println("长度: " + packetLength);
        System.out.println("时间戳(秒): " + timestamp_s);
        System.out.println("时间戳(微妙): " + timestamp_us);
        System.out.println("硬件类型: " + hardType);
        System.out.println("硬件地址长度: " + hardLength);
        System.out.println("操作: " + operation);

        System.out.println("ARP请求: " + arpRequest);
        System.out.println("ARP应答: " + arpReply);
        System.out.println("硬件类型-帧中继: " + frameRelay);
        System.out.println("硬件类型-IEEE802(令牌环)： " + tokenRing);
        System.out.println("协议类型-IP: " + protoIP);
        System.out.println("RARP请求: " + rarpRequest);
        System.out.println("RARP应答: " + rarpReply);
        System.out.println("数据: " + data);

        System.out.print("数据头部: ");
        for (byte b : arp.header)
            System.out.print(Integer.toHexString(b & 0xff) + " ");
        System.out.println("\n----------------------------------------------------------------------------------------------------");
    }

    /**
     * 进行 ARP 数据包抓取
     *
     * @return
     */
    public static ARPPacket arpCap(JpcapCaptor captor) {
        ARPPacket arp;

        Packet packet = captor.getPacket();
        if (packet instanceof ARPPacket) {
            arp = (ARPPacket) packet;
            return arp;
        }

        System.out.println("No ARP packet received within the timeout period.");
        return null;
    }

    /**
     * 获取网卡信息
     */
    public static void showAdapterInfo(NetworkInterface device) {
        System.out.println();
        System.out.println("-----------------------------------------网卡信息-----------------------------------------");
        int i = 1;

        String netInterfaceName = device.name;
        String netInterDescription = device.description;
        String dataLinkName = device.datalink_name;
        String dataLinkDesc = device.datalink_description;

        System.out.println("网卡" + (i++) + ": " + netInterfaceName + "(" + netInterDescription + ")");
        System.out.println("数据链路层信息: " + dataLinkName + "(" + dataLinkDesc + ")");

        // 网络接口地址
        for (NetworkInterfaceAddress addr : device.addresses) {
            InetAddress netInterAddress = addr.address;
            InetAddress netInterSubnet = addr.subnet;
            InetAddress netInterBroadcast = addr.broadcast;

            System.out.println("网络接口地址: " + netInterAddress + "  子网掩码: " + netInterSubnet + "  广播地址: " + netInterBroadcast);
        }

        System.out.print("MAC地址: ");
        int length = device.mac_address.length;
        int count = 1;

        for (byte b : device.mac_address) {
            System.out.print(Integer.toHexString(b & 0xff));

            if (count++ != length)
                System.out.print(":");
        }
        System.out.println("-----------------------------------------------------------------------------------------");
    }

    private static void sendArpPacket(JpcapSender sender, String senderIp, String senderMac,
                                      String targetIp, String targetMac, boolean isRequest) throws Exception {
        // 创建 ARP 数据包
        ARPPacket arpPacket = new ARPPacket();

        // 设置 ARP 数据包字段
        arpPacket.hardtype = ARPPacket.HARDTYPE_ETHER; // 硬件类型：以太网
        arpPacket.prototype = ARPPacket.PROTOTYPE_IP;  // 协议类型：IP
        arpPacket.operation = isRequest ? ARPPacket.ARP_REQUEST : ARPPacket.ARP_REPLY; // 操作类型
        arpPacket.hlen = 6; // MAC 地址长度
        arpPacket.plen = 4; // IP 地址长度

        // 设置发送者信息
        arpPacket.sender_hardaddr = parseMacAddress(senderMac);
        arpPacket.sender_protoaddr = InetAddress.getByName(senderIp).getAddress();

        // 设置目标信息
        arpPacket.target_hardaddr = parseMacAddress(targetMac);
        arpPacket.target_protoaddr = InetAddress.getByName(targetIp).getAddress();

        // 创建以太网帧
        EthernetPacket etherPacket = new EthernetPacket();
        etherPacket.src_mac = parseMacAddress(senderMac);
        etherPacket.dst_mac = isRequest ? parseMacAddress("FF:FF:FF:FF:FF:FF") : parseMacAddress(targetMac);
        etherPacket.frametype = EthernetPacket.ETHERTYPE_ARP;

        // 将以太网帧与 ARP 数据包关联
        arpPacket.datalink = etherPacket;

        // 发送 ARP 数据包
        sender.sendPacket(arpPacket);

        System.out.println();
        System.out.println("-----------------------------------------ARP request sent.-----------------------------------------");
        System.out.println("Sent ARP " + (isRequest ? "Request" : "Reply") + " packet:");
        System.out.println("Sender IP: " + senderIp + ", Sender MAC: " + senderMac);
        System.out.println("Target IP: " + targetIp + ", Target MAC: " + targetMac);
        System.out.println("---------------------------------------------------------------------------------------------------");
    }

    // 将 MAC 地址字符串解析为字节数组
    private static byte[] parseMacAddress(String mac) {
        String[] macParts = mac.split(":");
        byte[] macBytes = new byte[6];
        for (int i = 0; i < 6; i++) {
            macBytes[i] = (byte) Integer.parseInt(macParts[i], 16);
        }
        return macBytes;
    }
}

